"""
人脸数据库管理模块
负责人脸数据的增删改查操作
"""

import os
import json
import shutil
from typing import Dict, List, Any, Optional
import numpy as np


def add_face_to_database(name: str, image_path: str, face_database: Dict[str, Any]) -> bool:
    """
    添加人脸到数据库
    :param name: 人员姓名
    :param image_path: 图像路径
    :param face_database: 人脸数据库
    :return: 是否添加成功
    """
    try:
        from modules.face_features import extract_face_features
        
        # 提取人脸特征
        face_encodings = extract_face_features(image_path)
        
        if not face_encodings:
            print(f"未检测到人脸: {image_path}")
            return False
        
        # 确保data/face_images目录存在
        face_images_dir = os.path.join("data", "face_images")
        # 确保使用正确的编码处理中文路径
        face_images_dir = os.path.normpath(face_images_dir)
        # 在Windows系统上，确保路径编码正确
        if os.name == 'nt':
            face_images_dir = face_images_dir.encode('utf-8').decode('utf-8')
        try:
            if not os.path.exists(face_images_dir):
                os.makedirs(face_images_dir)
        except PermissionError:
            print(f"权限错误: 没有权限创建人脸图像目录 {face_images_dir}")
            return False
        except Exception as e:
            print(f"创建人脸图像目录失败: {e}")
            return False
            
        # 为每个人员创建单独的文件夹
        person_dir = os.path.join(face_images_dir, name)
        # 确保使用正确的编码处理中文路径
        person_dir = os.path.normpath(person_dir)
        # 在Windows系统上，确保路径编码正确
        if os.name == 'nt':
            person_dir = person_dir.encode('utf-8').decode('utf-8')
        try:
            if not os.path.exists(person_dir):
                os.makedirs(person_dir)
        except PermissionError:
            print(f"权限错误: 没有权限创建人员目录 {person_dir}")
            return False
        except Exception as e:
            print(f"创建人员目录失败: {e}")
            return False
            
        # 检查文件夹是否可写
        if not os.access(person_dir, os.W_OK):
            print(f"权限错误: 没有写入权限到文件夹 {person_dir}")
            return False
            
        # 生成目标文件路径
        filename = os.path.basename(image_path)
        target_path = os.path.join(person_dir, filename)
        # 确保使用正确的路径分隔符
        target_path = os.path.normpath(target_path)
        # 在Windows系统上，确保路径编码正确
        if os.name == 'nt':
            target_path = target_path.encode('utf-8').decode('utf-8')

        print('image_path',image_path)
        print('target_path',target_path)
       
        
        # 如果image_path和target_path是同一个文件（比如从摄像头直接保存的），则不需要复制
        if os.path.abspath(image_path) != os.path.abspath(target_path):
             # 如果目标文件已存在，添加序号
            counter = 1
            base_name, ext = os.path.splitext(filename)
            while os.path.exists(target_path):
                new_filename = f"{base_name}_{counter}{ext}"
                target_path = os.path.join(person_dir, new_filename)
                counter += 1
            try:
                # 复制图像到人员目录
                # 在Windows系统上，确保文件路径编码正确
                if os.name == 'nt':
                    image_path_for_copy = image_path.encode('utf-8').decode('utf-8')
                    target_path_for_copy = target_path.encode('utf-8').decode('utf-8')
                else:
                    image_path_for_copy = image_path
                    target_path_for_copy = target_path
                
                shutil.copy2(image_path_for_copy, target_path_for_copy)
                
                # 确保目标文件存在并使用正斜杠路径
                if not os.path.exists(target_path_for_copy):
                    print(f"复制文件失败: {target_path}")
                    return False
                    
                # 检查复制后的文件是否可写
                if not os.access(target_path_for_copy, os.W_OK):
                    print(f"权限错误: 没有写入权限到文件 {target_path}")
                    return False
            except PermissionError:
                print(f"权限错误: 没有权限复制文件到 {target_path}")
                return False
            except Exception as e:
                print(f"复制文件时发生异常: {e}")
                return False
        else:
            # 文件已经在正确位置，直接使用
            target_path = image_path
            
        # 使用正斜杠路径格式以确保跨平台兼容性
        target_path = target_path.replace("\\", "/")
        
        # 如果该人员已存在，则添加新的人脸特征；否则创建新人员
        if name in face_database:
            # 人员已存在，添加新的人脸特征
            person_data = face_database[name]
            if isinstance(person_data, dict) and "encodings" in person_data:
                # 新的数据结构
                for i, encoding in enumerate(face_encodings):
                    # 为每个人脸编码创建唯一标识
                    face_id = f"{name}_face_{len(person_data.get('encodings', [])) + i}"
                    person_data["encodings"].append({
                        "id": face_id,
                        "encoding": encoding.tolist(),  # 转换为列表以便JSON序列化
                        "image_path": target_path  # 使用复制后的文件路径（正斜杠格式）
                    })
            else:
                # 旧的数据结构，需要转换
                # 检查person_data的类型
                if isinstance(person_data, dict) and "encoding" in person_data:
                    # 旧的单图片数据结构
                    old_encoding = person_data["encoding"]
                    old_image_path = person_data.get("image_path", "")
                    face_database[name] = {
                        "encodings": [
                            {
                                "id": f"{name}_face_0",
                                "encoding": old_encoding,
                                "image_path": old_image_path
                            }
                        ]
                    }
                else:
                    # 最老的数据结构（只有编码）
                    face_database[name] = {
                        "encodings": [
                            {
                                "id": f"{name}_face_0",
                                "encoding": person_data,
                                "image_path": ""
                            }
                        ]
                    }
                # 添加新的人脸特征
                for i, encoding in enumerate(face_encodings):
                    face_id = f"{name}_face_{i+1}"
                    face_database[name]["encodings"].append({
                        "id": face_id,
                        "encoding": encoding.tolist(),
                        "image_path": target_path  # 使用复制后的文件路径（正斜杠格式）
                    })
        else:
            # 新人员，创建数据结构
            encodings_data = []
            for i, encoding in enumerate(face_encodings):
                face_id = f"{name}_face_{i}"
                encodings_data.append({
                    "id": face_id,
                    "encoding": encoding.tolist(),
                    "image_path": target_path  # 使用复制后的文件路径（正斜杠格式）
                })
            
            face_database[name] = {
                "encodings": encodings_data
            }
        
        return True
    except Exception as e:
        print(f"添加人脸到数据库失败: {e}")
        return False


def remove_face_from_database(name: str, face_database: Dict[str, Any]) -> bool:
    """
    从数据库中删除人脸
    :param name: 人员姓名
    :param face_database: 人脸数据库
    :return: 是否删除成功
    """
    try:
        if name in face_database:
            # 删除本地文件
            person_data = face_database[name]
            
            # 获取人员文件夹路径
            person_dir = os.path.join("data", "face_images", name)
            # 确保使用正确的编码处理中文路径
            person_dir = os.path.normpath(person_dir)
            # 在Windows系统上，确保路径编码正确
            if os.name == 'nt':
                person_dir = person_dir.encode('utf-8').decode('utf-8')
            
            # 处理不同的数据结构
            if isinstance(person_data, dict):
                if "encodings" in person_data:
                    # 新的数据结构：一个人对应多个人脸特征
                    for face_info in person_data["encodings"]:
                        image_path = face_info.get("image_path", "")
                        if image_path and os.path.exists(image_path):
                            try:
                                # 在Windows系统上，确保文件路径编码正确
                                if os.name == 'nt':
                                    image_path_for_delete = image_path.encode('utf-8').decode('utf-8')
                                else:
                                    image_path_for_delete = image_path
                                os.remove(image_path_for_delete)
                            except Exception as e:
                                print(f"删除文件失败 {image_path}: {e}")
                elif "image_path" in person_data:
                    # 旧的单图片数据结构
                    image_path = person_data.get("image_path", "")
                    if image_path and os.path.exists(image_path):
                        try:
                            os.remove(image_path)
                        except Exception as e:
                            print(f"删除文件失败 {image_path}: {e}")
            else:
                # 最老的数据结构（只有编码，没有图片路径）
                # 这种情况下我们无法删除文件，因为没有存储路径信息
                pass
            
            # 尝试删除人员文件夹（如果为空）
            try:
                # 在Windows系统上，确保文件夹路径编码正确
                if os.name == 'nt':
                    person_dir_for_delete = person_dir.encode('utf-8').decode('utf-8')
                else:
                    person_dir_for_delete = person_dir
                    
                if os.path.exists(person_dir_for_delete):
                    # 检查文件夹是否为空
                    if not os.listdir(person_dir_for_delete):
                        os.rmdir(person_dir_for_delete)
                    else:
                        # 如果文件夹不为空，也删除整个文件夹及其内容
                        shutil.rmtree(person_dir_for_delete)
            except Exception as e:
                print(f"删除人员文件夹失败 {person_dir}: {e}")
            
            # 从数据库中删除记录
            del face_database[name]
            return True
        return False
    except Exception as e:
        print(f"从数据库中删除人脸失败: {e}")
        return False


def remove_face_images(name: str, face_database: Dict[str, Any], image_indices: Optional[List[int]] = None) -> bool:
    """
    从数据库中删除指定人员的特定图片
    :param name: 人员姓名
    :param face_database: 人脸数据库
    :param image_indices: 要删除的图片索引列表，如果为None则删除所有图片
    :return: 是否删除成功
    """
    try:
        if name not in face_database:
            return False
            
        person_data = face_database[name]
        
        # 获取人员文件夹路径
        person_dir = os.path.join("data", "face_images", name)
        
        # 只处理新数据结构
        if isinstance(person_data, dict) and "encodings" in person_data:
            if image_indices is None:
                # 删除所有图片
                for face_info in person_data["encodings"]:
                    image_path = face_info.get("image_path", "")
                    if image_path and os.path.exists(image_path):
                        try:
                            os.remove(image_path)
                        except Exception as e:
                            print(f"删除文件失败 {image_path}: {e}")
                # 保留人员记录但清空图片
                person_data["encodings"] = []
            else:
                # 删除指定索引的图片
                # 从后往前删除以避免索引变化
                for idx in sorted(image_indices, reverse=True):
                    if 0 <= idx < len(person_data["encodings"]):
                        face_info = person_data["encodings"][idx]
                        image_path = face_info.get("image_path", "")
                        if image_path and os.path.exists(image_path):
                            try:
                                # 在Windows系统上，确保文件路径编码正确
                                if os.name == 'nt':
                                    image_path_for_delete = image_path.encode('utf-8').decode('utf-8')
                                else:
                                    image_path_for_delete = image_path
                                os.remove(image_path_for_delete)
                            except Exception as e:
                                print(f"删除文件失败 {image_path}: {e}")
                        # 从数据库中删除记录
                        person_data["encodings"].pop(idx)
                
                # 即使没有图片了，也保留人员记录，以便后续可以添加图片
                # 不再删除人员记录
                
            # 尝试删除人员文件夹（如果为空）
            try:
                # 在Windows系统上，确保文件夹路径编码正确
                if os.name == 'nt':
                    person_dir_for_delete = person_dir.encode('utf-8').decode('utf-8')
                else:
                    person_dir_for_delete = person_dir
                    
                if os.path.exists(person_dir_for_delete):
                    # 检查文件夹是否为空
                    if not os.listdir(person_dir_for_delete):
                        os.rmdir(person_dir_for_delete)
            except Exception as e:
                print(f"删除人员文件夹失败 {person_dir}: {e}")
            
            return True
        else:
            # 对于旧数据结构，使用原有的删除方法
            return remove_face_from_database(name, face_database)
    except Exception as e:
        print(f"从数据库中删除人脸图片失败: {e}")
        return False


def list_faces_in_database(face_database: Dict[str, Any]) -> List[str]:
    """
    列出数据库中所有人脸
    :param face_database: 人脸数据库
    :return: 人员姓名列表
    """
    return list(face_database.keys())


def get_person_face_count(face_database: Dict[str, Any], name: str) -> int:
    """
    获取指定人员的人脸图片数量
    :param face_database: 人脸数据库
    :param name: 人员姓名
    :return: 人脸图片数量
    """
    if name in face_database:
        person_data = face_database[name]
        if isinstance(person_data, dict) and "encodings" in person_data:
            return len(person_data["encodings"])
        else:
            # 旧数据结构，只有一个人脸
            return 1
    return 0